package bg.btanev.eightyfour.gwtfacade.converter;

import java.util.HashMap;
import java.util.LinkedHashMap;

import org.apache.commons.lang.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author B.Tanev
 *
 */
public class ConverterConfiguration {
	/**
	 * Logger for this class
	 */
	private static final Logger logger = LoggerFactory.getLogger(ConverterConfiguration.class);

	private final HashMap<Class<?>, Class<?>> associations = new LinkedHashMap<Class<?>, Class<?>>();

	public void addAssiciation(Class<?> clazz, Class<?> pairClazz, boolean bidirectional) {

		Validate.notNull(clazz);
		Validate.notNull(pairClazz);

		addPairClass(clazz, pairClazz);
		if (bidirectional) {
			addPairClass(pairClazz, clazz);
		}
	}

	public boolean containsClass(Class<?> clazz) {
		boolean result = associations.keySet().contains(clazz);
		if (!result) {
			result = associations.values().contains(clazz);
		}

		return result;
	}

	@SuppressWarnings("unchecked")
	public <R, S> Class<R> getAssociation(Class<S> source) {
		Class<R> result = (Class<R>) associations.get(source);
		if (result == null) {
			logger.info("getAssociation(Class<S>) - Pair class for '{}' not found.", source); //$NON-NLS-1$
		}

		return result;
	}

	private void addPairClass(Class<?> clazz, Class<?> pairClazz) {
		assert (clazz != null);
		assert (pairClazz != null);

		if (associations.containsKey(clazz)) {
			throw new IllegalStateException(String.format("Class '%s' already has an association.", clazz));
		}

		associations.put(clazz, pairClazz);
		logger
				.info(
						"addPairClass(Class<? extends Serializable>, Class<? extends Serializable>) associatio '{}' to '{}' added.", clazz, pairClazz); //$NON-NLS-1$
	}

	public void clearAllAssociations() {
		associations.clear();
	}

	public void removeAssociation(Class<?> clazz, boolean bidirectional) {
		Validate.notNull(clazz);

		if (bidirectional) {
			Class<?> pairClazz = associations.get(clazz);
			if (pairClazz != null) {
				associations.remove(pairClazz);
			}
		}

		associations.remove(clazz);
	}
}
